import pandas as pd
import Core.Gadget as Gadget
import Core.MongoDB as MongoDB
import numpy as np
import Core.IO as IO
import datetime
import math

def Top_stock_list(datetime1,datetime2, para_PE , para_PB, para_PEG, para_Payoutratio , order_factor, no_of_stocks):
    trades = database.find("Instruments", "Stock")
    symbols = []
    for trade in trades:
        if trade["DateTime2"] < Gadget.ToUTCDateTime(datetime1):
            continue
        symbol = trade["Symbol"]
        #print(symbol)
        symbols.append(symbol)

    datetime_cal = datetime1
    datetime_str = str(datetime1)+".000"
    datetime_cal = datetime1 + datetime.timedelta(hours=15)
    datetime_before = datetime_cal + datetime.timedelta(days=-32)
    df = pd.DataFrame(columns=('Symbol', "PE", "PB","PEG","Payoutration","Order"))  # 生成空的pandas表
    i = 0
    count = 0
    for symbol in symbols:
        count += 1
        factors_PE = database.find("Factor", "PriceEarningNetIncomeTTM", datetime_before, datetime_cal,
                                   query={"Symbol": symbol})
        if len(factors_PE) == 0:
            continue
        factors_PE = factors_PE[-1]
        factors_PB = database.find("Factor", "BookToMarket", datetime_before, datetime_cal, query={"Symbol": symbol})
        if len(factors_PB) == 0:
            continue
        factors_PB = factors_PB[-1]
        factors_Growth = database.find("Factor", "GrowthEarning1Y_by_zhu", datetime_before, datetime_cal,
                                       query={"Symbol": symbol})
        if len(factors_Growth) == 0:
            continue
        factors_Growth = factors_Growth[-1]
        if factors_Growth["Remark"] == "L" or factors_Growth["Value"] == 0:
            continue
        quotes = database.find("Quote", symbol + "_Time_86400_Bar", datetime1, datetime2)
        if len(quotes) < 2:
            continue
        quote_now = quotes[-1]
        quote_reportdate = quotes[0]
        if quote_now["TradeStatus"] == "交易" and quote_reportdate["TradeStatus"] == "交易":
            cap_now = quote_now["Close"] * quote_now["Values"]['TotalShares']
            cap_reportdate = quote_reportdate["Close"] * quote_reportdate["Values"]['TotalShares']
        else:
            continue

        # dividend = factors_Dividend[-1]["AccumulatedDividend"]
        fundamentals = database.find("Fundamental", symbol + "_Fundamental",
                                     query={"ReportDate": datetime_str})  # CashEquivalents
        if len(fundamentals) == 0:
            continue
        if "NetIncome1" not in fundamentals[0]["Values"]:
            continue
        netincome = fundamentals[0]["Values"]["NetIncome1"]
        if netincome <= 0:
            continue
        if "PayDividend" not in fundamentals[0]["Values"]:
            continue
        Payoutratio = fundamentals[0]["Values"]["PayDividend"] / netincome

        PE = (cap_now / cap_reportdate) * factors_PE["Value"]
        PB = (cap_now / cap_reportdate) * (1 / factors_PB["Value"])
        PEG = PE / (factors_Growth["Value"]*100)
        if PE < para_PE and PE > 0 and PB > 0 and PB < para_PB and PEG < para_PEG and PEG > 0 and Payoutratio > para_Payoutratio:
            df.loc[i] = [symbol, PE, PB, PEG, Payoutratio, None]
            i += 1
            #print(symbol, PE, PB, PEG, Payoutratio)

    if order_factor == "PE":
        df_reorder = df.sort_values(by=[order_factor], ascending=True)  # 从小到大
        df_reorder = df_reorder.iloc[0:no_of_stocks,0]
        df_reorder = np.array(df_reorder)  # np.ndarray()
        df_reorder = df_reorder.tolist()  # list
    #print(df_reorder)
    return df_reorder

def Backtest(dates, para_PE , para_PB, para_PEG, para_Payoutratio , order_factor, no_of_stocks):
    net = 1
    print(dates[0]+datetime.timedelta(days=60),net)
    for i in range(len(dates)-1):
        stock_list = Top_stock_list(dates[i],dates[i]+ datetime.timedelta(days=60), para_PE , para_PB, para_PEG, para_Payoutratio , order_factor, no_of_stocks)
        if len(stock_list) == 0:
            print(dates[i+1]+datetime.timedelta(days=60), net)
            continue
        return_of_stock = 0
        for j in range(len(stock_list)):
            symbol = stock_list[j]
            quotes = database.find("Quote", symbol + "_Time_86400_Bar", dates[i] + datetime.timedelta(days=60), dates[i+1] + datetime.timedelta(days=60))
            if len(quotes) < 2:
                continue
            quote_sell = quotes[-1]
            quote_buy = quotes[0]
            sellprice = quote_sell["Close"]/quote_sell["AdjFactor"]
            buyprice = quote_buy["Close"]/quote_buy["AdjFactor"]

            return_of_stock += (sellprice - buyprice)/buyprice
        net = net * (1 + return_of_stock/len(stock_list))
        print(dates[i+1]+datetime.timedelta(days=60),net)



from Core.Config import Config
config = Config()
database = config.DataBase()
datetime1 = datetime.datetime(2008, 5, 2)
datetime1 = Gadget.ToUTCDateTime(datetime1)
datetime2 = datetime.datetime(2018, 11, 21)
datetime2 = Gadget.ToUTCDateTime(datetime2)
dates = Gadget.GenerateReportDates(datetime1,datetime2)
Backtest(dates, 12, 0.8, 0.8, 0, "PE" , 20)#PE,PB,PEG,Payoutratio,排序因子,股票池股票数量